package com.chapter1;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * @Created by xiangty
 */
public class Test {

    /**
     * 抛出异常API  add()/remove()
     */
    public static void queueTest() {
        // capacity 容量为3的阻塞队列

        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("A")); // true
        System.out.println(blockingQueue.add("B")); // true
        System.out.println(blockingQueue.add("C")); // true

        // 超过容量，提示队列满异常： Exception in thread "main" java.lang.IllegalStateException: Queue full
//        System.out.println(blockingQueue.add(4));

        System.out.println("队列首位元素：" + blockingQueue.element());

        System.out.println("-------输出队列信息：");
        System.out.println(blockingQueue.remove()); // A
        System.out.println(blockingQueue.remove()); // B
        System.out.println(blockingQueue.remove()); // C

        // 队列为空，提示没有元素异常： java.util.NoSuchElementException
//        System.out.println(blockingQueue.remove());
    }

    /**
     * 不抛出异常 offer()/poll()  无参方法
     */
    public static void queueTest2() {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        System.out.println(blockingQueue.offer("a")); // true
        System.out.println(blockingQueue.offer("b")); // true
        System.out.println(blockingQueue.offer("c")); // true
        System.out.println(blockingQueue.offer("d")); // false 不抛出异常

        System.out.println("队列首位元素：" + blockingQueue.element());

        System.out.println("-------输出队列信息：");
        System.out.println(blockingQueue.poll()); // a
        System.out.println(blockingQueue.poll()); // b
        System.out.println(blockingQueue.poll()); // c
        System.out.println(blockingQueue.poll()); // null
    }

    /**
     * 等待 put()/take()
     */
    public static void queueTest3() {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        try {
            blockingQueue.put("A");
            blockingQueue.put("B");
            blockingQueue.put("C");
//            blockingQueue.put("D"); // 队列没有位置了，一直等待
            System.out.println(blockingQueue.take()); // A
            System.out.println(blockingQueue.take()); // B
            System.out.println(blockingQueue.take()); // C
//            System.out.println(blockingQueue.take()); // 队列没有数据了，一直等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 等待阻塞（等待超时）
     */
    public static void queueTest4() {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        try {
            blockingQueue.offer("A");
            blockingQueue.offer("B");
            blockingQueue.offer("C");
            blockingQueue.offer("D", 2, TimeUnit.SECONDS); // 等待2秒就退出
            System.out.println(blockingQueue.poll()); // A
            System.out.println(blockingQueue.poll()); // B
            System.out.println(blockingQueue.poll()); // C
            System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS)); // null
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        List list1 = new ArrayList();
        list1.add(1);
        list1.add(1);
        list1.add(1);
        list1.add(1);
        List list = new ArrayList(list1);
        System.out.println(list);

//        List list = new ArrayList();
//        list.add("a");
//        list.add(2);
//        list.add("b");
//
//        System.out.println(list);
//        list.remove(2);
//        System.out.println(list);

//        queueTest3();
        /**
         * ACID:原子性、一致性、隔离性、持久性
         * CAP：一致性、可用性、分区容错性
         * BASE：基本可用、软状态、最终一致性
         *
         * RDB:快照，每隔固定的时间和操作的次数将数据备份一份，优点是没有冗余数据、恢复时间比较快，缺点是存在数据缺失。
         * AOF：日志，记录所有的写操作命令，优点是可以恢复所有数据，缺点是存在数据冗余、数据量大的时候恢复时间比较长。
         *
         * 缓存穿透：数据库和缓存都没有数据，大量请求重复请求和访问的时候，直接访问到数据库上面，造成数据库的压力过大。
         *          解决方案：设置缓存空值和失效时间、布隆过滤器
         *
         * 缓存击穿：热点key突然失效，大量请求访问这个热点key，直接穿过缓存访问到数据库上面，造成数据库压力过大。
         *          解决方案：将热点key的失效时间设置长一些
         *
         * 缓存雪崩：大量请求集中访问的时候，大量的缓存集中失效，造成请求直接访问数据库，数据库链接过多、压力过大甚至宕机造成服务雪崩。
         *          解决方案：将缓存失效时间设置的分开，避免集中失效。
         *
         */

//        collectionMethod();

//        volatile // 可见性、不保证原子性、禁止指令重排

//        AtomicInteger atomicInteger = new AtomicInteger(0);
//        atomicInteger.getAndIncrement();// 加1
//        atomicInteger.get();
//        atomicInteger.getAndAdd(-1);// 加-1
//        atomicInteger.compareAndSet(0, 100); // 比较并替换，如果值为0的时候，将值替换为100
//
//        // AtomicReference 可以存在复杂对象
//        AtomicReference<String> atomicReference = new AtomicReference<>("1");
//        atomicReference.compareAndSet("1", "100");
//        atomicReference.get();

        /**
         * CAS：compareAndSwap 比较并替换，本质是一个自旋锁，do-while一直从内存中取出最新数据，然后用期望值去替换最新值。
         *
         * ABA问题：多个线程操作同一个变量的时候，快的线程将变量值从a改成b,然后从b又改成a，慢的线程在拿到变量时候虽然值还是a，
         *          但是这个是存在安全问题的。
         *          解决方案：AtomicStampedReference
         */

//        AtomicStampedReference atomicStampedReference = new AtomicStampedReference("a", 100);
//        int stamp = atomicStampedReference.getStamp();
//        atomicStampedReference.compareAndSet("a", "b", stamp, stamp+1);

//        CountDownLatch countDownLatch = new CountDownLatch(5);
//        countDownLatch.countDown();
//        countDownLatch.getCount();

//        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
//            System.out.println("----------");
//        });
//
//        for (int i = 0; i < 5; i++) {
//            final int num = i;
//            new Thread(() -> {
//                try {
//                    System.out.println(Thread.currentThread().getName() + "   " + num);
//                    cyclicBarrier.await();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                } catch (BrokenBarrierException e) {
//                    e.printStackTrace();
//                }
//            }, "A").start();
//        }

//        Semaphore semaphore = new Semaphore(3);
//        for (int i = 0; i < 8; i++) {
//            final int num = i;
//            new Thread(()->{
//                try {
//                    semaphore.acquire();
//                    System.out.println(num +" 开始");
//                    TimeUnit.SECONDS.sleep(3);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                semaphore.release();
//                System.out.println(num +" 结束");
//            }, "B").start();
//        }

//        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
//        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
//
//        // 指的是“以固定的频率”执行，period（周期）指的是两次成功执行之间的时间
//        // 比如，scheduleAtFixedRate(command, 5, 2, second)，第一次开始执行是5s后，假如执行耗时1s，那么下次开始执行是7s后，再下次开始执行是9s后。如果方法执行超过了2秒，则在方法执行结束后，立刻开始执行下一次任务。
//        scheduledThreadPool.scheduleAtFixedRate(() -> {
//        }, 1, 2, TimeUnit.SECONDS);
//        // 指的是“以固定的延时”执行，delay（延时）指的是一次执行终止和下一次执行开始之间的延迟
//        // 还是上例，scheduleWithFixedDelay(command, 5, 2, second)，第一次开始执行是5s后，假如执行耗时1s，执行完成时间是6s后，那么下次开始执行是8s后，再下次开始执行是11s后
//        scheduledThreadPool.scheduleWithFixedDelay(() -> {
//        }, 1, 2, TimeUnit.SECONDS);

//        ThreadPoolExecutor(int corePoolSize,                      // 默认线程数
//                            int maximumPoolSize,                  // 最大线程数
//                            long keepAliveTime,                   // 线程闲置等待时长
//                            TimeUnit unit,                        // 线程闲置等待时间单位
//                            BlockingQueue<Runnable> workQueue,    // 阻塞队列
//                            ThreadFactory threadFactory,          // 线程工厂
//                            RejectedExecutionHandler handler)     // 拒绝策略

//        ThreadPoolExecutor.AbortPolicy
//        ThreadPoolExecutor.CallerRunsPolicy
//        ThreadPoolExecutor.DiscardPolicy
//        ThreadPoolExecutor.DiscardOldestPolicy

//        Lock lock = new ReentrantLock();
//        lock.lock();
//        Condition condition = lock.newCondition();
//        try {
//            condition.await();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        condition.signal();
//        condition.signalAll();
//        lock.unlock();

//        ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//        Lock readLock = readWriteLock.readLock();
//        readLock.lock();
//        readLock.unlock();
//
//        Lock writeLock = readWriteLock.writeLock();
//        writeLock.lock();
//        writeLock.unlock();

//        SynchronousQueue synchronousQueue = new SynchronousQueue();

    }

    private static void collectionMethod() {
        List<String> list = new ArrayList<>();
        List<String> list1 = new Vector<>();
        List<Object> list2 = new CopyOnWriteArrayList<>();
        List<Object> list3 = Collections.synchronizedList(new ArrayList<>());
        list.isEmpty();
        list.add("1");
        list.size();
        list.get(1);
        list.remove(1);
        Iterator<String> i = list.iterator();
        while (i.hasNext()) {
            i.next();
        }

        Set<Long> set = new HashSet<>();
        Set<Long> set1 = new CopyOnWriteArraySet<>();
        Set<Long> set2 = Collections.synchronizedSet(new HashSet<>());
        set.add(2L);
        set.isEmpty();
        set.contains(2L);
        Iterator i2 = set.iterator();
        while (i2.hasNext()) {
            i2.next();
        }

        Map<String, Object> map = new HashMap<>();
        Map<Integer, Long> map1 = Collections.synchronizedMap(new HashMap<>());
        ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
        map.put("bbb", "aa");
        map.put("ccc", "dddd");
        map.remove("bbb");
        map.size();
        map.containsKey("dddd");
    }

}
